package nbpservice;

import java.io.IOException;
import java.math.BigDecimal;
import java.net.URL;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Scanner;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import entities.ExchangeRate;
import exceptions.NoSuchCurrencyException;
import exceptions.NoSuchDocumentException;

public class NbpServiceImpl implements NbpService
{

	private Document getExchangeRateXmlDocument(String newest_exchange_rate_xml_document_name) throws SAXException, IOException, ParserConfigurationException
	{
		Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(address_prefix + newest_exchange_rate_xml_document_name + ".xml");

		return document;
	}

	private ArrayList<String> getAvailableExchangeRateXmlDocumentsList() throws IOException
	{
		ArrayList<String> available_exchange_rate_xml_documents_list = new ArrayList<String>();
		URL url = new URL(available_xml_documents_list_file);
		Scanner skaner = new Scanner(url.openStream());
		while (skaner.hasNext())
		{
			available_exchange_rate_xml_documents_list.add(skaner.next());
		}
		skaner.close();
		
		available_exchange_rate_xml_documents_list.remove(0);
		Collections.reverse(available_exchange_rate_xml_documents_list);

		return available_exchange_rate_xml_documents_list;
	}

	private Document getNewestExchangeRateXmlDocument(String type) throws NoSuchDocumentException, IOException, SAXException, ParserConfigurationException
	{
		ArrayList<String> available_exchange_rate_xml_documents_list = getAvailableExchangeRateXmlDocumentsList();
		String newest_exchange_rate_xml_document_name = null;
		
		for (String doc_name : available_exchange_rate_xml_documents_list)
		{
			if (doc_name.startsWith(type))
			{
				newest_exchange_rate_xml_document_name = doc_name;
				break;
			}
		}

		if (newest_exchange_rate_xml_document_name == null)
			throw new NoSuchDocumentException();

		Document document = getExchangeRateXmlDocument(newest_exchange_rate_xml_document_name);

		return document;
	}

	public Map<String, ExchangeRate> getNewestExchangeRateMap(String type) throws NoSuchDocumentException, IOException, SAXException, ParserConfigurationException, ParseException
	{

		Document document = getNewestExchangeRateXmlDocument(type);
		return NBPXmlDocumentToExchangeRateParser.toMap(document);
	}

	public ExchangeRate getNewestExchangeRateForGivenCurrencyCode(String currency_code) throws NoSuchDocumentException, IOException, SAXException, ParserConfigurationException, ParseException,
			NoSuchCurrencyException
	{
		ExchangeRate result = getNewestExchangeRateMap(LIST_A).get(currency_code.toUpperCase());
		if (result == null)
		{
			throw new NoSuchCurrencyException();
		}

		return result;
	}

	public BigDecimal getNewestDecimalExchangeRateForGivenCurrencyCode(String currency_code) throws NoSuchDocumentException, IOException, SAXException, ParserConfigurationException, ParseException,
			NoSuchCurrencyException
	{
		return getNewestExchangeRateForGivenCurrencyCode(currency_code).getRealExchangeRate();
	}
	
	
	private List<String> getNbpXmlDocumentNamesWithPublicationDateAfter (Date date) throws IOException
	{
		ArrayList<String> available_exchange_rate_xml_document_names_list = getAvailableExchangeRateXmlDocumentsList();
		List<String> result = new ArrayList<String>();
		
		for (String exchange_rate_xml_document_name : available_exchange_rate_xml_document_names_list)
		{
			if (ParseNbpXmlDocumentNameToDate(exchange_rate_xml_document_name).after(date))
			{
				result.add(exchange_rate_xml_document_name);
			}
			else break;
		}
		
		return result;
	}
	
	private Date ParseNbpXmlDocumentNameToDate (String nbp_xml_document_name)
	{
		int year = Integer.parseInt(nbp_xml_document_name.substring(5, 7)) + 2000;
		int month = Integer.parseInt(nbp_xml_document_name.substring(7, 9));
		int day = Integer.parseInt(nbp_xml_document_name.substring(9, 11));
		
		return new Date(year, month, day);
	}
	
	private List<Document> getNbpXmlDocumentsWithPublicationDateAfter (Date date) throws IOException, SAXException, ParserConfigurationException
	{
		List<Document> result = new ArrayList<Document>();
		
		for (String doc_name : getNbpXmlDocumentNamesWithPublicationDateAfter (date))
		{
			result.add(getExchangeRateXmlDocument(doc_name));
		}
		
		return result;
	}
	
	public List<ExchangeRate> getExchangeRatesWithPublicationDateAfter (Date date) throws IOException, SAXException, ParserConfigurationException, ParseException
	{
		List<ExchangeRate> result = new ArrayList<ExchangeRate>();
		
		for (Document document : getNbpXmlDocumentsWithPublicationDateAfter (date))
		{
			for (ExchangeRate exchange_rate : NBPXmlDocumentToExchangeRateParser.toList(document))
			{
				result.add(exchange_rate);
			}
		}
		
		return result;
	}
	
	
	
	
	public static class NBPXmlDocumentToExchangeRateParser
	{
		public static List<ExchangeRate> toList (Document xml_document) throws ParseException
		{
			List<ExchangeRate> exchange_rate_list = new ArrayList<ExchangeRate>();

			NodeList node_list = xml_document.getElementsByTagName(xml_element_name);
			Node node;
			NodeList sub_node_list;

			Date exchange_rate_date = getDateFromNBPXmlDocument(xml_document);

			for (int node_number = 0; node_number < node_list.getLength(); node_number++)
			{
				node = node_list.item(node_number);
				sub_node_list = node.getChildNodes();

				exchange_rate_list.add(
						new ExchangeRate(exchange_rate_date, sub_node_list.item(1).getTextContent(), Integer.parseInt(sub_node_list.item(3).getTextContent()), sub_node_list.item(5).getTextContent(),
								new BigDecimal(sub_node_list.item(7).getTextContent().replaceAll(",", "."))));

			}
			return exchange_rate_list;
		}
	
	
		public static Map<String, ExchangeRate> toMap (Document xml_document) throws ParseException
		{
			Map<String, ExchangeRate> exchange_rate_map = new HashMap<String, ExchangeRate>();
	
			for (ExchangeRate exchange_rate : toList (xml_document))
			{
				exchange_rate_map.put(exchange_rate.getCurrencyCode(), exchange_rate);
			}
			return exchange_rate_map;
		}
		
		public static Date getDateFromNBPXmlDocument(Document document) throws ParseException
		{
			String date = document.getElementsByTagName("data_publikacji").item(0).getTextContent();
			DateFormat date_formatter = new SimpleDateFormat("yyyy-MM-dd");
			Date exchange_rate_date = date_formatter.parse(date);

			return exchange_rate_date;
		}
	}
	
}













